package com.xh.common.thread.ext.executor;

import com.xh.common.thread.ext.queue.LevelBlockingQueue;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 自定义的线程池
 * 线程池分配逻辑：
 * 1.将线程池分为多个level的子线程池，每个子线程池只会执行等于或高于当前level的任务。
 * 2.任务会被优先分配到低level的子线程池，如果无法满足，则会层层递进分配到高level的子线程池。
 */
public class LevelThreadPoolExecutor extends AbstractExecutorService implements LevelExecutorService {

    public static final String TAG = "LevelThreadPoolExecutor";


    // 目前只支持RUNNING、SHUTDOWNED
    public static final int RUNNING = 0;
    public static final int SHUTDOWNED = 1;
    public static final int STOP = 2;
    public static final int TIDYING = 3;
    public static final int TERMINATED = 4;

    // 线程池的级别数
    private final int mLevel;
    // 默认的配置
    private ThreadPolicy mDefaultPolicy;
    // 线程构建工厂
    private ThreadFactory mThreadFactory;

    private AtomicInteger mSequence = new AtomicInteger();

    // 内部执行器
    private final LevelInternalExecutor[] mExecutors;
    // 线程池状态
    private AtomicInteger mCtl = new AtomicInteger(RUNNING);

    LevelExecutorDetector mDetector;
    // 任务队列
    LevelBlockingQueue<Command> mWorkQueue;

    public LevelThreadPoolExecutor(LevelConfig[] levels, LevelBlockingQueue<Command> workQueue,
                                   ThreadFactory threadFactory) {
        if (levels == null || levels.length <= 0) {
            throw new IllegalArgumentException();
        }

        if (workQueue == null || threadFactory == null) {
            throw new NullPointerException();
        }

        mLevel = levels.length;
        mWorkQueue = workQueue;
        mThreadFactory = threadFactory;
        mExecutors = new LevelInternalExecutor[mLevel];

        for (int i = 0; i < levels.length; i++) {
            mExecutors[i] = new LevelInternalExecutor(this, i, levels[i]);
        }
    }

    @Override
    public void setLevelExecutorDetector(LevelExecutorDetector detector) {
        mDetector = detector;
    }

    public ThreadFactory getThreadFactory() {
        return mThreadFactory;
    }

    @Override
    public void setDefaultPolicy(ThreadPolicy policy) {
        mDefaultPolicy = policy;
    }

    @Override
    public void execute(Runnable runnable) {
        if (runnable == null) {
            throw new NullPointerException();
        }
        executeInternal(new Command(runnable, mDefaultPolicy));
    }

    public int getStatus() {
        return mCtl.get();
    }

    @Override
    public void execute(Runnable runnable, ThreadPolicy policy) {
        if (runnable == null) {
            throw new NullPointerException();
        }

        ThreadPolicy p = (policy == null ? mDefaultPolicy : policy);
        Command command = new Command(runnable, p);

        int l = command.getLevel();
        if (l < 0 || l >= mLevel) {
            throw new IllegalArgumentException();
        }

        executeInternal(command);
    }

    private void executeInternal(Command command) {
        // 设置序号，因为系统优先级队列不是一个稳定的排序。
        command.setSequence(mSequence.incrementAndGet());

        if (mDetector != null) {
            mDetector.onExecute(command);
        }

        // 这里不需要加锁，如果同一时刻有很多任务时，从每个子线程池中抢夺资源，谁抢到算谁的，只要内部同步好，保证不会多抢占。
        int level = command.getLevel();
        for (int i = 0; i <= level; i++) {
            if (!isRunning()) {
                return;
            }

            if (mExecutors[i].execute(command)) {
                return;
            }
        }

        if (!isRunning()) {
            return;
        }

        mWorkQueue.offer(command);

        // 如果放进去后又停了，就移除
//        if (!isRunning()) {
//            mWorkQueue.remove(command);
//            return;
//        }

        if (mDetector != null) {
            mDetector.onOfferNormalQueue(command);
        }
    }

    @Override
    public void shutdown() {
        advanceRunState(SHUTDOWNED);
    }

    @Override
    public List<Runnable> shutdownNow() {
        return Collections.emptyList();
    }

    @Override
    public boolean isShutdown() {
        return mCtl.get() >= SHUTDOWNED;
    }

    public boolean isRunning() {
        return mCtl.get() < SHUTDOWNED;
    }

    @Override
    public boolean isTerminated() {
        return mCtl.get() >= TERMINATED;
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
        return false;
    }

    private void advanceRunState(int targetState) {
        for (;;) {
            int c = mCtl.get();
            if (runStateAtLeast(c, targetState) ||
                    mCtl.compareAndSet(c, targetState));
            break;
        }
    }

    private static boolean runStateLessThan(int c, int s) {
        return c < s;
    }

    private static boolean runStateAtLeast(int c, int s) {
        return c >= s;
    }

}
